//
//  KBAddressBookManager.m
//  AddressBookDemo
//
//  Created by wulanzhou on 2017/5/10.
//  Copyright © 2017年 wulanzhou. All rights reserved.
//

#import "KBAddressBookManager.h"
#import <AddressBook/AddressBook.h>
#import <Contacts/Contacts.h>
#import <ContactsUI/ContactsUI.h>
#import "ContactNode.h"

#define isIOS9 ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9.0 ? YES : NO)

NSString * const KBAddressBookLoadCompeted  = @"KBAddressBookLoadCompeted";

void AddressBookDataChangeCallback(ABAddressBookRef addressBook, CFDictionaryRef info, void *context);

@interface KBAddressBookManager ()
@property (nonatomic, assign) ABAddressBookRef addressBook;
@property (nonatomic, strong) CNContactStore *contactStore;
@property (atomic, assign) BOOL isLoading;
@end

@implementation KBAddressBookManager

@synthesize allContacts= _allContacts;
@synthesize sortKeys= _sortKeys;

+ (instancetype)shareManger{
    static KBAddressBookManager *manger = nil;
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (!manger) {
            manger = [[KBAddressBookManager alloc]init];
        }
    });
    return manger;
}

- (instancetype)init{
    self = [super init];
    if (self) {
        if (isIOS9) {
            _contactStore = [[CNContactStore alloc] init];
        }else{
            _addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
        }
        _isLoading = NO;
        _allContacts = nil;
        _sortKeys = nil;
        
        [self registerAddressBookObeserver];
        
    }
    
    return self;
}

/**
 通读录权限设置
 
 @param block 通读录权限回调
 */
- (void)canReadAddressBookStatusBlock:(KBAddressBookCanReadBlock)block{
    
    // 1.获取授权状态
    if (isIOS9) {
        NSLog(@"ios 9 以上系统");
        CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
        if(status == CNAuthorizationStatusAuthorized){ //能够自由访问联系人
            block(YES,status);
        }else if (status == CNAuthorizationStatusNotDetermined){ //是否允许访问联系人，当应用第一次安装在设备上时将处于此状态
            
            [self.contactStore requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
                
                if (granted) {
                    block(YES,CNAuthorizationStatusAuthorized);
                }else{
                    block(NO,CNAuthorizationStatusDenied);
                }
            }];
            
        }else{
            block(NO,status);
        }
        
    }else{
       NSLog(@"ios 9 以下系统");
        ABAuthorizationStatus authStatus = ABAddressBookGetAuthorizationStatus();
        if (authStatus == kABAuthorizationStatusNotDetermined) {
            ABAddressBookRequestAccessWithCompletion(_addressBook, ^(bool granted, CFErrorRef error) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    if (error) {
                        //拒绝访问
                        block(NO,kABAuthorizationStatusDenied);
                    }else{
                        block(YES,0);
                    }
                });
            });
        }else if (authStatus == kABAuthorizationStatusAuthorized){
            block(YES,0);
        }else{
            block(NO,authStatus);
        }
    }
}

- (void)loadContactsCompletion:(KBAddressBookLoadFinishedBlock)completion{
    
    if (self.isLoading) {
        NSLog(@"正在加载联系人");
        return;
    }
    self.isLoading = YES;
    //开启线程加载联系人
    [NSThread detachNewThreadSelector:@selector(readContactsWithCompletion:) toTarget:self withObject:completion];
    
}
- (void)readContactsWithCompletion:(KBAddressBookLoadFinishedBlock)completion{

    __block NSMutableDictionary *_allContactsDic = [NSMutableDictionary dictionaryWithCapacity:0];
    __block NSMutableArray *_sortKeyList = [NSMutableArray arrayWithCapacity:0];
    if(isIOS9){
        
        // 3.2.创建联系人的请求对象
        // keys决定这次要获取哪些信息,比如姓名/电话
        NSArray *fetchKeys = @[CNContactGivenNameKey,CNContactMiddleNameKey,CNContactFamilyNameKey,CNContactBirthdayKey,CNContactNicknameKey,CNContactOrganizationNameKey,CNContactPhoneticGivenNameKey,CNContactPhoneticMiddleNameKey,CNContactPhoneticFamilyNameKey,CNContactImageDataKey,CNContactPhoneNumbersKey];
        CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:fetchKeys];
        
        // 3.3.请求联系人
        NSError *error = nil;
        [self.contactStore enumerateContactsWithFetchRequest:request error:&error usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
            
            if (contact) {
                ContactNode *node = [[ContactNode alloc] initContactNodeWithContact:contact];
                
                NSString *key = [node getContactSortKey];
                //添加到相应的分区中
                id aList = [_allContactsDic objectForKey:key];
                NSMutableArray *bList = [[NSMutableArray alloc] initWithCapacity:2];
                if (aList && [aList isKindOfClass:[NSArray class]]) {
                    [bList addObjectsFromArray:aList];
                }
                [bList addObject:node];
                [_allContactsDic setValue:bList forKey:key];
                
                //添加key
                if (![_sortKeyList containsObject:key]) {
                    [_sortKeyList addObject:key];
                }
            }
        }];
        
    }else{
        
        //取得所有地址本的信息
        CFArrayRef personList = ABAddressBookCopyArrayOfAllPeople(self.addressBook);
        CFIndex pCount = CFArrayGetCount(personList);
        for (int i = 0; i < pCount; ++i) {
            ABRecordRef onePerson = CFArrayGetValueAtIndex(personList, i);
            ContactNode *node = [[ContactNode alloc] initContactNodeWithRecord:onePerson];
            
            NSString *key = [node getContactSortKey];
            //添加到相应的分区中
            id aList = [_allContactsDic objectForKey:key];
            NSMutableArray *bList = [[NSMutableArray alloc] initWithCapacity:2];
            if (aList && [aList isKindOfClass:[NSArray class]]) {
                [bList addObjectsFromArray:aList];
            }
            [bList addObject:node];
            [_allContactsDic setValue:bList forKey:key];
            
            //添加key
            if (![_sortKeyList containsObject:key]) {
                [_sortKeyList addObject:key];
            }
        }
    }
    
    //排序
    NSMutableArray *tempSortArray = [NSMutableArray array];
    //对键值排序
    [tempSortArray addObjectsFromArray:[_sortKeyList sortedArrayUsingSelector:@selector(compare:)]];
    //调整#的位置
    NSInteger index = [tempSortArray indexOfObject:@"#"];
    if (index != NSNotFound) {
        [tempSortArray removeObjectAtIndex:index];
        [tempSortArray addObject:@"#"];
    }
    _sortKeys = tempSortArray;
    _allContacts = _allContactsDic;
    self.isLoading = NO;
    
    //NSLog(@"_sortKeys =%@",_sortKeys);
    //NSLog(@"_allContacts =%d",[_allContacts count]);
    NSLog(@"联系人加载完成!!");
    
    if (completion) {
        completion();
    }
    
    //联系人加载完成
    [[NSNotificationCenter defaultCenter] postNotificationName:KBAddressBookLoadCompeted object:nil];
}

/**
 清空联系人
 */
- (void)clearContacts{
    
    if (isIOS9) {
    
        @synchronized (self.contactStore) {
            NSArray *fetchKeys = @[CNContactGivenNameKey,CNContactMiddleNameKey,CNContactFamilyNameKey,CNContactBirthdayKey,CNContactNicknameKey,CNContactOrganizationNameKey,CNContactPhoneticGivenNameKey,CNContactPhoneticMiddleNameKey,CNContactPhoneticFamilyNameKey,CNContactPhoneNumbersKey];
            CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:fetchKeys];
            
            //初始化方法
            CNSaveRequest * saveRequest = [[CNSaveRequest alloc] init];
            // 3.3.请求联系人
            NSError *error = nil;
            [self.contactStore enumerateContactsWithFetchRequest:request error:&error usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
                [saveRequest deleteContact:[contact mutableCopy]];
            }];
            BOOL ret = [self.contactStore executeSaveRequest:saveRequest error:nil];
            if (ret) {
                NSLog(@"清空联系人成功！");
            }else{
                NSLog(@"清空联系人失败！");
            }
        }
       
    }else{
    
        @synchronized (self.addressBook) {
            //取得所有地址本的信息
            CFArrayRef personList = ABAddressBookCopyArrayOfAllPeople(self.addressBook);
            CFIndex pCount = CFArrayGetCount(personList);
            for (int i = 0; i < pCount; ++i) {
                ABRecordRef onePerson = CFArrayGetValueAtIndex(personList, i);
                BOOL ret = ABAddressBookRemoveRecord(self.addressBook, onePerson, NULL);
                if (ret) {
                    NSLog(@"删除成功！");
                }else{
                    NSLog(@"删除失败！");
                }
            }
            ABAddressBookSave(self.addressBook, NULL);
        }
        
    }
}

/**
 恢复联系人
 
 @param contacts 联系人集合
 */
- (void)restoreContacts:(NSArray <ContactNode *> *)contacts{

    if (contacts && [contacts count]>0) {
        __weak __typeof(&*self)weakSelf = self;
        if (isIOS9) {
            
            @synchronized (self.contactStore) {
                //初始化方法
                CNSaveRequest * saveRequest = [[CNSaveRequest alloc] init];
                [contacts enumerateObjectsUsingBlock:^(ContactNode * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                    //[weakSelf addContact:obj];
                    //添加联系人
                    [saveRequest addContact:[weakSelf createContactWithNode:obj] toContainerWithIdentifier:nil];
                }];
                
                BOOL success =[self.contactStore executeSaveRequest:saveRequest error:nil];
                
                if(success){
                    NSLog(@"新增联系人成功!");
                }else{
                    NSLog(@"新增联系人失败!");
                }
            }
            
        }else{
            [contacts enumerateObjectsUsingBlock:^(ContactNode * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                [weakSelf addContact:obj];
            }];
        }
        
        
    }

}

- (CNMutableContact *)createContactWithNode:(ContactNode *)node{

    //创建联系人对象
    CNMutableContact * contact = [[CNMutableContact alloc] init];
    //设置名字
    contact.givenName = node.firstName;
    contact.middleName = node.middleName;
    contact.familyName = node.lastName;
    contact.nickname = node.nickName;
    contact.organizationName = node.companyName;
    //contact.phoneticGivenName = node.firstPinyin;
    //contact.phoneticMiddleName = node.middlepinyin;
    
    //设置生日
    if (node.birthday) {
        NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
        
        NSDateComponents *weekdayComponents = [gregorian components:(NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay) fromDate:node.birthday];
        
        contact.birthday = weekdayComponents;
    }
    
    //设置头像
    if (node.imageData) {
        contact.imageData = node.imageData;
    }
    
    
    //联系人电话号码
    NSMutableArray *addPhones=[NSMutableArray arrayWithCapacity:0];
    for (NSString *item in node.phoneList) {
        [addPhones addObject:[CNLabeledValue labeledValueWithLabel:CNLabelPhoneNumberiPhone value:[CNPhoneNumber phoneNumberWithStringValue:item]]];
    }
    contact.phoneNumbers = addPhones;
    
    return contact;
}

- (void)addContact:(ContactNode *)node{
    
    //创建一条空的联系人
    ABRecordRef record = ABPersonCreate();
    CFErrorRef error;
    //设置联系人的名字
    ABRecordSetValue(record, kABPersonFirstNameProperty, (__bridge CFTypeRef)node.firstName, &error);
    ABRecordSetValue(record, kABPersonMiddleNameProperty, (__bridge CFTypeRef)node.middleName, &error);
    ABRecordSetValue(record, kABPersonLastNameProperty, (__bridge CFTypeRef)node.lastName, &error);
    ABRecordSetValue(record, kABPersonNicknameProperty, (__bridge CFTypeRef)node.nickName, &error);
    ABRecordSetValue(record, kABPersonOrganizationProperty, (__bridge CFTypeRef)node.companyName, &error);
    //设置头像
    if (node.imageData) {
        ABPersonSetImageData (record,( __bridge CFDataRef )node.imageData, NULL);
    }
    //设置生日
    ABRecordSetValue(record, kABPersonBirthdayProperty, (__bridge CFTypeRef)node.birthday, &error);
    
    // 添加联系人电话号码以及该号码对应的标签名
    ABMutableMultiValueRef multi = ABMultiValueCreateMutable(kABPersonPhoneProperty);
    for (NSString *num in node.phoneList) {
        ABMultiValueAddValueAndLabel(multi,(__bridge CFStringRef)num, kABPersonPhoneMobileLabel, NULL);
    }
    
    ABRecordSetValue(record, kABPersonPhoneProperty, multi, &error);
    //ABAddressBookRef addressBook = nil;
    //如果为iOS6以上系统，需要等待用户确认是否允许访问通讯录。
    //addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
    //等待同意后向下执行
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);
    ABAddressBookRequestAccessWithCompletion(self.addressBook, ^(bool granted, CFErrorRef error){                                                     dispatch_semaphore_signal(sema);
    });
    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    //将新建联系人记录添加如通讯录中
    BOOL success= ABAddressBookAddRecord(self.addressBook, record, &error);
    //保存通讯录数据
    ABAddressBookSave(self.addressBook, &error);
    
    if(success){
        NSLog(@"新增联系人成功!");
    }else{
        NSLog(@"新增联系人失败!");
    }

}

#pragma mark -私有方法
- (void)registerAddressBookObeserver {
    dispatch_async(dispatch_get_main_queue(),^(void){
        
        if (isIOS9) { //联系人发生改变通知
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveContactChanged:) name:CNContactStoreDidChangeNotification object:nil];
        }else{
            ABAddressBookRegisterExternalChangeCallback(self.addressBook, AddressBookDataChangeCallback, (__bridge void *)(self));
        }
    });
}

void AddressBookDataChangeCallback(ABAddressBookRef addressBook, CFDictionaryRef info, void *context) {
    if(context) {
        id objContext = (__bridge id)(context);
        if([objContext isKindOfClass:[KBAddressBookManager class]]) {
            NSLog(@"检测到本地数据库发生了变化,函数(%s)", __FUNCTION__);
            [[KBAddressBookManager shareManger] loadContactsCompletion:nil];
        }
    }
}

- (void)receiveContactChanged:(NSNotification *)notification{
    
    NSDictionary *item=[notification userInfo];
    if (item) {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"检测到本地数据库发生了变化,函数(%s)", __FUNCTION__);
            [self loadContactsCompletion:nil];
        });
    }
    /*
     if ([item.allKeys containsObject:@"CNNotificationSourcesKey"]) {
     NSArray *arr=[item objectForKey:@"CNNotificationSourcesKey"];
     //表示有存储内容的变更
     
     if ([arr count]>0) {
     NSLog(@"检测到本地数据库发生了变化,函数(%s),%@", __FUNCTION__, notification);
     //NSLog(@"检测到本地数据库发生了变化,%@", [[item objectForKey:@"CNNotificationSourcesKey"] class]);
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
     [self loadAllContact];
     });
     }
     }
     
     */
    
}

@end
